﻿using System;
using System.Reflection;

namespace Smile.Mvvm.Mediator
{
    internal class WeakAction
    {
        // @Properties
        public Type ParameterType
        {
            get
            {
                return _parameterType;
            }
        }

        public bool IsAlive
        {
            get
            {
                return _targetRef.IsAlive;
            }
        }


        // @Public
        public WeakAction(object target, MethodInfo method, Type parameterType)
        {
            if (target == null)
            {
                _targetRef = null;
            }
            else
            {
                _targetRef = new WeakReference(target);
            }

            _method = method;

            _parameterType = parameterType;
            if (_parameterType == null)
            {
                _delegateType = typeof(Action);
            }
            else
            {
                _delegateType = typeof(Action<>).MakeGenericType(parameterType);
            }
            
        }

        public Delegate CreateAction()
        {
            if (_targetRef == null)
            {
                return _method.CreateDelegate(_delegateType);
            }
            else
            {
                try
                {
                    var target = _targetRef.Target;
                    if (target != null)
                    {
                        return _method.CreateDelegate(_delegateType, target);
                    }
                }
                catch
                {
                }
            }

            return null;
        }


        // @Private
        private readonly Type           _delegateType;
        private readonly Type           _parameterType;
        private readonly MethodInfo     _method;
        private readonly WeakReference  _targetRef;
    }

#if !NETFX_CORE
    public static class MethodInfoExtension
    {
        public static Delegate CreateDelegate(this MethodInfo method, Type type)
        {
            return Delegate.CreateDelegate(type, method);
        }

        public static Delegate CreateDelegate(this MethodInfo method, Type type, object firstArgument)
        {
            return Delegate.CreateDelegate(type, firstArgument, method);
        }
    }
#endif
}
